package emby.expr;

import java.lang.reflect.Array;
import java.util.List;
import java.util.Map;

import emby.EmbyRuntime;
import emby.err.TypeError;
import emby.lang.Scope;
import emby.overload.OverloadIndex;
import emby.writer.IEmbyCodifier;

/**
 * The AST representation of an index operator call.
 * <br>
 * For example, as in
 * 	a[2]
 * 	or
 * 	"hello"[0]
 * @author Justin
 */
public class IndexVariable  extends Variable {
	private static final long serialVersionUID = -3196343663957938965L;
	public Expression arg1;
	public Expression index;
	public IndexVariable(Expression arg1, Expression index){
		super(null);
		this.arg1 = arg1;
		this.index = index;
	}
	@Override
	public Object eval(Scope s) {
		if(EmbyRuntime.echo){
			emby.util.Print.println("Evaluating index expression "+arg1+"["+index+"])");
		}
		Object o = arg1.eval(s);

		Object ind = index.eval(s);
		if (o instanceof OverloadIndex) { // if operator is overloaded
			return ((OverloadIndex) o).get_index(getLine(),ind);
		}else if (o instanceof Map){
			Map<Object, ?> m = (Map<Object, ?>) o;
			return m.get(ind);
		}else if (o instanceof List){
			if(!(ind instanceof Integer)){
				throw new TypeError(getLine(), "Lists can only be indexed by integers");
			}
			List<?> l = (List<?>) o;
			return l.get((Integer)ind);
		}
		else if (o instanceof String) {
			if(!(ind instanceof Integer)){
				throw new TypeError(getLine(), "Strings can only be indexed by integers");
			}
			char c = ((String) o).charAt(  (Integer)ind);
			char[] carray = {c};
			return new String(carray);
		}
		else {
				try{
				return Array.get(o, (Integer)ind);
				}catch( IllegalArgumentException e){
					throw new TypeError(getLine(), o+"("+o.getClass()+")" + " cannot be indexed with "+ind +"("+ind.getClass()+")");
				}catch (ClassCastException e){
					throw new TypeError(getLine(), o+"("+o.getClass()+")" + " cannot be indexed with "+ind +"("+ind.getClass()+")");
				}
			}
	}

	public void setVar(Scope s, Object value){
		if(EmbyRuntime.echo){
			emby.util.Print.println("Assigning "+value+" to index expression "+this.toString());
		}


		Object var = arg1.eval(s);
		Object ind = index.eval(s);
		if(!(var instanceof OverloadIndex)){
			throw new TypeError(getLine(),var.getClass()+" does not support assignment through indexing");
		}
		else{
			((OverloadIndex)var).set_index(getLine(), ind,value);
		}
	}

	/**
	 * Read-only access does not apply to indexed expressions.
	 * @see Variable#isReadOnly()
	 */
	public boolean isReadOnly(){
		return false;
	}

	public String toString(){
		return "{IndexExpression: "+arg1+"["+index+"]}";
	}

	public void codify(IEmbyCodifier ec){
		ec.index(arg1, index);
	}
}